package com.dqx.opengl_es_demo.cylinder;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import com.dqx.opengl_es_demo.circle.CircleRenderer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/**
 * 圆柱体渲染器（圆柱体由2个圆底加1个圆筒组成，圆筒一样可以拆解
 * 成由多个正方形组成，每个正方形又由2个三角形组成）
 */
public class CylinderRenderer implements GLSurfaceView.Renderer {
    //存储顶点坐标的缓冲区对象
    FloatBuffer vertexBuffer;
    //顶点着色器代码
    private final String vertexShaderCode =
            "uniform mat4 vMatrix;\n" +
                    "varying vec4 vColor;\n" +
                    "attribute vec4 vPosition;\n" +
                    "void main(){\n" +
                    "    gl_Position=vMatrix*vPosition;\n" +
                    "    if(vPosition.z!=0.0){\n" +
                    "        vColor=vec4(0.0,0.0,0.0,1.0);\n" +
                    "    }else{\n" +
                    "        vColor=vec4(0.9,0.9,0.9,1.0);\n" +
                    "    }\n" +
                    "}";
    //片元着色器代码
    private final String fragmentShaderCode =
            "precision mediump float;\n" +
                    "varying vec4 vColor;\n" +
                    "void main(){\n" +
                    "    gl_FragColor=vColor;\n" +
                    "}";
    //顶点坐标集合
    private float[] vertexCoord;

    //浮点型占4个字节长度
    int FLOAT_BYTE_LENGTH = 4;

    //程序id
    int program;
    //顶点着色器id
    int vertexShader;
    //片元着色器id
    int fragmentShader;
    //顶点位置句柄
    int mPositionHandle;
    //相机矩阵
    private float[] mViewMatrix = new float[16];
    //投影矩阵
    private float[] mProjectMatrix = new float[16];
    //变化矩阵
    private float[] mMVPMatrix = new float[16];
    //变化矩阵句柄
    private int mMatrixHandler;
    //切割份数
    private int n = 360;
    //圆锥高度
    private float height = 2.0f;
    //圆锥底面半径
    private float radius = 1.0f;

    //圆形渲染器
    CircleRenderer circleRenderer;
    //圆形渲染器
    CircleRenderer circleRenderer2;

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //启用深度测试
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        //创建圆的顶点坐标
        vertexCoord = createPositions();
        //初始化缓冲区对象
        vertexBuffer = initFloatBuffer(vertexCoord);
        //创建程序
        program = creatProgram();

        circleRenderer = new CircleRenderer();
        circleRenderer.onSurfaceCreated(gl, config);

        circleRenderer2 = new CircleRenderer();
        circleRenderer2.height = height;
        circleRenderer2.onSurfaceCreated(gl, config);
    }


    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        //设置视图窗口的位置及大小
        GLES20.glViewport(0, 0, width, height);

        //宽高比
        float ratio = (float) width / height;

        float left = -ratio;//相对观察点近面的左边距
        float right = ratio;//相对观察点近面的右边距
        float bottom = -1;//相对观察点近面的下边距
        float top = 1;//相对观察点近面的上边距
        float near = 3;//相对观察点近面距离
        float far = 20;//相对观察点远面距离
        //设置透视投影矩阵
        Matrix.frustumM(mProjectMatrix, 0, left, right, bottom, top, near, far);

        float eyeX = 1.0f;//相机位置x坐标
        float eyeY = -10.0f;//相机位置y坐标
        float eyeZ = -4.0f;//相机位置z坐标
        float centerX = 0.0f;//相机观察的目标点x坐标
        float centerY = 0.0f;//相机观察的目标点y坐标
        float centerZ = 0.0f;//相机观察的目标点z坐标
        float upX = 0.0f;//相机UP向量X分量
        float upY = 1.0f;//相机UP向量Y分量
        float upZ = 0.0f;//相机UP向量Z分量
        //设置相机位置
        Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);

        //计算变换矩阵 = 投影矩阵* 相机矩阵
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        //清除深度缓存和颜色缓存
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        //绘制
        draw();

        circleRenderer.mMVPMatrix = mMVPMatrix;
        circleRenderer.onDrawFrame(gl);

        circleRenderer2.mMVPMatrix = mMVPMatrix;
        circleRenderer2.onDrawFrame(gl);
    }

    /**
     * 创建圆筒面的顶点坐标
     *
     * @return
     */
    private float[] createPositions() {
        ArrayList<Float> pos = new ArrayList<>();
        float angDegSpan = 360f / n;
        for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
            pos.add((float) (radius * Math.sin(i * Math.PI / 180f)));
            pos.add((float) (radius * Math.cos(i * Math.PI / 180f)));
            pos.add(height);
            pos.add((float) (radius * Math.sin(i * Math.PI / 180f)));
            pos.add((float) (radius * Math.cos(i * Math.PI / 180f)));
            pos.add(0.0f);
        }
        float[] d = new float[pos.size()];
        for (int i = 0; i < d.length; i++) {
            d[i] = pos.get(i);
        }
        return d;
    }

    /**
     * 初始化缓冲区对象
     *
     * @param buffer
     * @return
     */
    private FloatBuffer initFloatBuffer(float[] buffer) {
        FloatBuffer fb = ByteBuffer.allocateDirect(buffer.length * FLOAT_BYTE_LENGTH)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(buffer);
        fb.position(0);
        return fb;
    }

    /**
     * 创建着色器，并返回着色器对象id
     *
     * @param type       着色器类型
     * @param shaderCode 着色器代码
     * @return
     */
    private int loadShader(int type, String shaderCode) {
        //创建着色器对象
        int shader = GLES20.glCreateShader(type);
        //加载着色器代码源
        GLES20.glShaderSource(shader, shaderCode);
        //编译着色器
        GLES20.glCompileShader(shader);
        return shader;
    }

    /**
     * 创建程序
     */
    private int creatProgram() {
        //程序对象id
        int program = 0;
        //创建顶点着色器
        vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        //创建片元着色器
        fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        //创建程序对象
        program = GLES20.glCreateProgram();
        //将顶点着色器加到程序中
        GLES20.glAttachShader(program, vertexShader);
        //将片段着色器加到程序中
        GLES20.glAttachShader(program, fragmentShader);
        //连接着色器
        GLES20.glLinkProgram(program);
        return program;
    }

    /**
     * 绘制三角形
     */
    public void draw() {
        //使用程序
        GLES20.glUseProgram(program);

        //获取变换矩阵vMatrix成员句柄
        mMatrixHandler = GLES20.glGetUniformLocation(program, "vMatrix");
        //指定vMatrix的值
        GLES20.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);

        //获取顶点着色器的vPosition属性句柄
        mPositionHandle = GLES20.glGetAttribLocation(program, "vPosition");
        //启用位置属性的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //设置位置坐标值
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * FLOAT_BYTE_LENGTH, vertexBuffer);
//        int mColorHandle=GLES20.glGetUniformLocation(mProgram,"vColor");
//        GLES20.glEnableVertexAttribArray(mColorHandle);
//        GLES20.glUniform4fv(mColorHandle,1,colors,0);
        //绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, vertexCoord.length / 3);
    }

    /**
     * 释放着色器资源
     */
    private void relese() {
        GLES20.glDeleteShader(vertexShader);
        GLES20.glDeleteShader(fragmentShader);
        GLES20.glDeleteProgram(program);
    }
}
